﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AIProject.Search
{
    class AlphaBeta
    {
        private NodeInfo nodeInfo;
        private int nodeCount;
        private int extNodes;
        private int fullDepth;
        private Boolean stop;

        public int NodeCount
        {
            get
            {
                return nodeCount;
            }
            set
            {
            }
        }

        public int ExtNodes
        {
            get
            {
                return this.extNodes;
            }
            set
            {
            }
        }


        public Boolean Stop
        {
            get
            {
                return this.stop;
            }
            set
            {
                this.stop = value;
            }
        }

        public AlphaBeta(NodeInfo nodeInfo, int fullDepth)
        {
            this.nodeInfo = nodeInfo;
            this.fullDepth = fullDepth;
            this.stop = false;
        }

        public double maxValue(Node visit, double alpha, double beta, Boolean extended, Boolean quiescent)
        {
            if (stop)
            {
                return nodeInfo.utility(visit);
            }

            List<Pylos.Action> actions;
            Node child;
            Boolean doExtension = false;
            double childValue = -1;
            Boolean hasValue = false;
            nodeCount++;

            if (!quiescent)
            {
                actions = visit.State.getActions();
                if (actions.Count == 0 || nodeInfo.isTerminal(visit))
                {
                    return nodeInfo.utility(visit);
                }
                else if (visit.Cost >= nodeInfo.DepthLimit)
                {
                    double utility = nodeInfo.utility(visit);
                    if (nodeInfo.DepthLimit == fullDepth)
                    {
                        if (!extended && utility >= 4)
                        {
                            doExtension = true;
                            extNodes++;
                        }
                        else
                        {
                            //return utility;
                            return minValue(visit, alpha, beta, doExtension, true);
                        }
                    }
                    else
                    {
                        return utility;
                    }
                }

                foreach (Pylos.Action arc in actions)
                {
                    if (stop)
                    {
                        return (hasValue ? childValue : nodeInfo.utility(visit));
                    }

                    child = (Node)visit.clone();
                    child.update(arc);

                    childValue = minValue(child, alpha, beta, doExtension, false);
                    alpha  = Math.Max(alpha, childValue);
                    hasValue = true;

                    if (alpha >= beta)
                    {
                        return alpha;
                    }
                }

                return alpha;
            }
            else
            {
                if (nodeInfo.isTerminal(visit) || visit.Cost >= 6)
                {
                    return nodeInfo.utility(visit);
                }

                List<Pylos.Action> removals = nodeInfo.generateRemovals(visit);

                if (removals.Count == 0)
                {
                    return nodeInfo.utility(visit);
                }

                foreach (Pylos.Action action in removals)
                {
                    child = (Node)visit.clone();
                    child.update(action);

                    alpha = Math.Max(alpha, minValue(child, alpha, beta, doExtension, true));

                    if (alpha >= beta)
                    {
                        return alpha;
                    }
                }
                return alpha;
            }
        }

        public double minValue(Node visit, double alpha, double beta, Boolean extended, Boolean quiescent)
        {
            if (stop)
            {
                return nodeInfo.utility(visit);
            }
            
            List<Pylos.Action> actions;
            Node child;
            Boolean doExtension = false;
            double childValue = -1;
            Boolean hasValue = false;
            nodeCount++;

            if (!quiescent)
            {
                actions = visit.State.getActions();
                if (actions.Count == 0 || nodeInfo.isTerminal(visit))
                {
                    return nodeInfo.utility(visit);
                }
                else if (visit.Cost >= nodeInfo.DepthLimit)
                {
                    double utility = nodeInfo.utility(visit);
                    if (nodeInfo.DepthLimit == fullDepth)
                    {
                        if (!extended && utility >= 4)
                        {
                            doExtension = true;
                        }
                        else
                        {
                            //return utility;
                            return maxValue(visit, alpha, beta, doExtension, true);
                        }
                    }
                    else
                    {
                        return utility;
                    }
                }

                foreach (Pylos.Action arc in actions)
                {
                    if (stop)
                    {
                        return (hasValue ? childValue : nodeInfo.utility(visit));
                    }

                    child = (Node)visit.clone();
                    child.update(arc);

                    childValue = maxValue(child, alpha, beta, doExtension, false);
                    beta = Math.Min(beta, childValue);
                    hasValue = true;

                    if (beta <= alpha)
                    {
                        return beta;
                    }
                }
                return beta;
            }
            else
            {
                if (nodeInfo.isTerminal(visit) || visit.Cost >= 6)
                {
                    return nodeInfo.utility(visit);
                }

                List<Pylos.Action> removals = nodeInfo.generateRemovals(visit);

                if (removals.Count == 0)
                {
                    return nodeInfo.utility(visit);
                }

                foreach(Pylos.Action action in removals)
                {
                    child = (Node)visit.clone();
                    child.update(action);

                    beta = Math.Min(beta, maxValue(child, alpha, beta, doExtension, true));

                    if (beta <= alpha)
                    {
                        return beta;
                    }
                }
                return beta;
            }
        }

        public void reset()
        {
            nodeCount = 0;
            extNodes = 0;
        }
    }
}
